<?php
/**
 * 本地化类
 * 
 * 配置文件默认存放在config/locale/$locale下，类似于
 * <pre>
 *   /config/locale/zh_cn
 *        _opt.php
 *        _message.php
 * </pre>
 * 
 * 可以在_opt.php配置文件中添加
 *   $opt["key"] = "value";
 * 如果上面的key是headers，如
 * <code>
 *  $opt["headers"] = array(
 *		"content-type" => "text/html;charset=utf-8"
 *	); 
 * </code>
 * 则可以用sendHeaders方法将这些报头发送到浏览器端
 * 
 * 可以在_message.php配置文件中添加
 *    $message["key"] = "value";
 * 
 * 从1.1.0开始起，可以在模块中定义消息文件：
 * - $module-dir/_message.en_us.php
 * - $module-dir/_message.zh_cn.php
 * 然后就可以使用：
 * - x("~@模块名.消息名")
 * 取得其中的消息值
 * 
 * 从1.1.0开始，可以在_message.php中设置
 * <code>
 * $message["a.b.c.d"] = "e";
 * </code>
 * 相当于：
 * <code>
 * $message["a"]["b"]["c"]["d"] = "e";
 * </code>
 *
 * @package if
 * @subpackage util.locale
 * @since 1.0
 */
class ILocale extends IObject {
	private $messages = array();
	private $opts = array();
	private $timezone = "";

	private $name;
	private static $defaultName;
	
	/**
	 * 默认参数值
	 * 
	 * 用于fromXxx中的判断
	 *
	 * @since 1.0
	 */
	const LOCALE_PARAM = "locale";
	
	/**
	 * 所有已经设置的区域
	 *
	 * @var array
	 * @since 1.0
	 */
	private static $locales = array();
	
	/**
	 * Enter description here...
	 *
	 * @var boolean
	 */
	private $isDefault;
	
	/**
	 * 构造器
	 *
	 * @param string $name Locale名称，如en_us,zh_cn
	 * @param boolean $isDefault 是否使用默认的设置
	 * @since 1.0
	 */
	function __construct($name, $isDefault = false) {
		$this->name = $name;
		$this->isDefault = $isDefault;
		
		//配置
		$config = o("@locale.{$name}");
		if (!is_array($config) || empty($config)) {
			$config = o("@locale.tpl");
		}
		
		//timezone
		if (isset($config["timezone"])) {
			$this->timezone = $config["timezone"];
		}
		
		//messages
		$app = IApplication::singleton();
		if (isset($config["message"])) {
			$compilerKey = "locale.{$name}.messages";
			$messageInCompiler = if_array_from_compiler($compilerKey);
			if (!empty($messageInCompiler)) {
				$this->messages = $messageInCompiler;
			}
			else {
				//加载模块中的消息配置
				foreach (IApplication::singleton()->modules() as $moduleName => $dir) {
					$messageFile = $dir . "/_message.{$name}.php";
					if (is_file($messageFile)) {
						unset($message);
						require($messageFile);
						if (isset($message) && is_array($message)) {
							$message = $this->_dotToArray($message);
							foreach ($message as $key => $_message) {
								if (substr($key, 0, 1) != "@") {//当前模块配置
									if (!isset($this->messages["@" . $moduleName])) {
										$this->messages["@" . $moduleName] = array();
									}
									$this->messages["@" . $moduleName][$key] = $_message;
								}
								elseif (is_array($_message)) {//其他模块配置
									if (!isset($this->messages[$key])) {
										$this->messages[$key] = array();
									}
									$this->messages[$key] = if_array_merge_recursive($this->messages[$key], $_message);
								}
							}
						}
					}
				}
				
				//加载用户自定义消息
				$file = str_replace("%{locale}", $name, $config["message"]);
				$files = $app->relativeFile(dirname($file))->lists(basename($file));
				foreach ($files as $file) {
					unset($message);
					require($file->absPath());
					if (isset($message) && is_array($message)) {
						$this->messages = if_array_merge_recursive($this->messages, $this->_dotToArray($message));
					}
				}
				
				if_array_to_compiler($compilerKey, $this->messages);
			}
		}
		
		//opts
		if (isset($config["opt"])) {
			$compilerKey = "locale.{$name}.opts";
			$optInCompiler = if_array_from_compiler($compilerKey);
			if (!empty($optInCompiler)) {
				$this->opts = $optInCompiler;
			}
			else {
				$file = str_replace("%{locale}", $name, $config["opt"]);
				$file = $app->relativeFile($file);
				if ($file->exists()) {
					require($file->absPath());
					if (isset($opt) && is_array($opt)) {
						$this->opts = $opt;
					}
				}
				if_array_to_compiler($compilerKey, $this->opts);
			}
		}
		self::$locales[] = $this;
	}
	
	private function _dotToArray($array) {
		$ret = array();
		foreach ($array as $key => $value) {
			$ret = if_array_set($ret, $key, $value);
		}
		return $ret;
	}
	
	/**
	 * 区域名
	 *
	 * @return string
	 * @since 1.0
	 */
	function name() {
		return $this->name;
	}
	
	/**
	 * 取得当前的时区
	 * 
	 * 返回如Asia/Chongqing
	 *
	 * @return string
	 * @since 1.0
	 */
	function timezone() {
		return $this->timezone;
	}
	
	/**
	 * 取得配置的头信息
	 *
	 * @return array
	 * @since 1.0
	 */
	function headers() {
		if (isset($this->opts["headers"]) && is_array($this->opts["headers"])) {
			return $this->opts["headers"];
		}
		return array();
	}
	
	/**
	 * 发送头信息
	 *
	 * @return boolean
	 * @since 1.0
	 */
	function sendHeaders() {
		if (headers_sent()) {
			return false;
		}
		foreach ($this->headers() as $name => $content) {
			header($name . ":" . $content);
		}
		return true;
	}
	
	/**
	 * 取得所有消息
	 *
	 * @return array
	 * @since 1.0
	 */
	function messages() {
		return $this->messages;	
	}
	
	/**
	 * 取得所有配置
	 *
	 * @return array
	 * @since 1.0
	 */
	function opts() {
		return $this->opts;
	}
	
	/**
	 * 取得消息
	 *
	 * @param string $key 键
	 * @return string|null
	 * @since 1.0
	 */
	function message($key) {
		return if_array_get($this->messages, $key);
	}
	
	/**
	 * 取得配置
	 *
	 * @param string $key 键
	 * @return mixed
	 * @since 1.0
	 */
	function opt($key) {
		return if_array_get($this->opts, $key);
	}
	
	/**
	 * 设置默认的区域
	 *
	 * @param string $name 默认的区域名
	 * @since 1.0
	 */
	static function setDefault($name) {
		self::$defaultName = $name;
	}
	
	/**
	 * 取得看默认的locale
	 *
	 * @return string
	 * @since 1.0
	 */
	static function defaultName() {
		//默认的
		
		if (!self::$defaultName) {
			self::$defaultName = o("@locale.default_name");
		}
		return self::$defaultName;
	}
	
	/**
	 * 从浏览器取得本地化对象
	 * 
	 * @return ILocale
	 * @since 1.0
	 */
	static function byBrowser($default = null) {
		if ($default) {
			self::setDefault($default);
		}
		if (!isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) {
			return new ILocale(self::defaultName(), true);
		}
		list($langStr) = explode(";", $_SERVER["HTTP_ACCEPT_LANGUAGE"]);
		$langs = explode(",", $langStr);
		if (empty($langs)) {
			if (!self::defaultName()) {
				throw new IException("failed to get locale from browser", 0x100035);
			}
			else {
				return new ILocale(self::defaultName(), true);
			}
		}
		else {
			$locale = $langs[0];
			if (strstr($locale, "-")) {
				list($lang, $country) = explode("-", $locale);
				$locale = $lang . "_" . strtoupper($country);
			}
			return new ILocale($locale);
		}
	}
	
	/**
	 * 从cookie中获取本地化对象
	 *
	 * @param string $cookieName cookie名
	 * @return ILocale
	 * @since 1.0
	 */
	static function byCookie($cookieName = self::LOCALE_PARAM) {
		$locale = ICookie::get($cookieName);
		if (!$locale) {
			$locale = self::defaultName();
			return new ILocale($locale, true);
		}
		else {
			return new ILocale($locale);
		}
	}
	
	static function bySession($sessionName = self::LOCALE_PARAM) {
		$locale = ISession::singleton()->get($sessionName);
		if (!$locale) {
			$locale = self::defaultName();
			return new ILocale($locale, true);
		}
		else {
			return new ILocale($locale);
		}
	}
	
	/**
	 * 从URL中获取本地化对象
	 *
	 * @param string $paramName 参数名
	 * @return ILocale
	 * @since 1.0
	 */
	static function byUrl($paramName = self::LOCALE_PARAM) {
		$locale = IRequest::singleton()->param($paramName);
		if (!$locale) {
			$locale = self::defaultName();
			return new ILocale($locale, true);
		}
		else {
			return new ILocale($locale);
		}
	}
	
	/**
	 * 取得当前设置过的区域
	 *
	 * @return array
	 * @since 1.0
	 */
	static function locales() {
		return self::$locales;
	}
	
	/**
	 * 取得当前设置的本地化对象
	 *
	 * @return ILocale
	 * @since 1.0
	 */
	static function current() {
		if (empty(self::$locales)) {
			return self::auto();
		}
		$locales = self::$locales;
		return array_pop($locales);
	}
	
	function isDefault() {
		return $this->isDefault;
	}
	
	/**
	 * Enter description here...
	 *
	 * @return ILocale
	 */
	static function auto() {
		$track = o("@locale.track");
		if (!is_array($track) || empty($track)) {
			return new ILocale(self::defaultName());
		}
		
		foreach ($track as $value) {
			if (is_array($value) && isset($value[0])) {
				if ($value[0] == "url") {
					$param = isset($value[1])?$value[1]:self::LOCALE_PARAM;
					$locale = self::byUrl($param);
					if (!$locale->isDefault()) {
						return $locale;
					}
				}
				else if ($value[0] == "cookie") {
					$param = isset($value[1])?$value[1]:self::LOCALE_PARAM;
					$locale = self::byCookie($param);
					if (!$locale->isDefault()) {
						return $locale;
					}
				}
				else if ($value[0] == "session") {
					$param = isset($value[1])?$value[1]:self::LOCALE_PARAM;
					$locale = self::bySession($param);
					if (!$locale->isDefault()) {
						return $locale;
					}
				}
				else if ($value[0] == "browser") {
					$locale = self::byBrowser();
					if (!$locale->isDefault()) {
						return $locale;
					}
				}
			}
			else if (is_string($value) && $value == "browser") {
				$locale = self::byBrowser();
				if (!$locale->isDefault()) {
					return $locale;
				}
			}
		}
		return new ILocale(self::defaultName(), true);
	}
	
	/**
	 * 设置新的区域名称
	 * 
	 * 可以动态改变当前已经加载的本地化对象
	 *
	 * @param string $name 新的区域名称
	 * @since 1.1.1
	 */
	function setName($name) {
		$this->__construct($name);
	}
}

?>